import * as fs from 'node:fs';
import * as path from 'node:path';
import logger from '../logger';

export interface DBFileOptions<T> {
    /**
     * 文件存储路径
     */
    filePath: string;
    /**
     * 初始化数据
     */
    initData: T;
    /**
     * 内存数据持久化频率，即：节流时间 单位 ms
     * @default 3000
     */
    flushInterval?: number;
    /**
     * 是否启用文件监听
     * @default false
     */
    watchFile?: boolean;
    /**
     * 是否自动存储，开启后，不需要主动执行update
     */
    autoSave?: boolean;
    /**
     * 加载已存储文件信息为数据
     * @param filePath 
     * @returns 
     */
    fileToData?: (filePath: string) => T
    /**
     * 将数据转换为文件内容的函数
     * 
     * @param data 要转换的数据对象
     * @returns 返回可以直接写入文件的字符串或二进制数据
     */
    dataToFile?: (data: T) => string | NodeJS.ArrayBufferView
    /**
     * 文件变化时的回调函数
     * @param newData 新的数据
     * @param oldData 旧的数据
     */
    onFileChange?: (newData?: T, oldData?: T) => void;
}

const defaults: Omit<Required<DBFileOptions<any>>, 'filePath' | 'initData'> = {
    flushInterval: 3000,
    watchFile: false,
    autoSave: false,
    fileToData: (filePath) => JSON.parse(fs.readFileSync(filePath, 'utf8')),
    dataToFile: (data) => JSON.stringify(data.toString(), null, 2),
    onFileChange: () => {},
}

export class DBFile<T = any> {
    options: Required<DBFileOptions<T>>
    data: T
    save_timer?: Timer
    private watcher?: fs.FSWatcher
    private isUpdating: boolean = false;
    private lastUpdateTime: number = 0;
    private readonly DEBOUNCE_TIME = 100; // 防抖时间，单位毫秒

    constructor(options: DBFileOptions<T>) {
        this.options = {
            ...defaults,
            ...options,
        };
        
        const {
            filePath,
            initData,
            autoSave,
            dataToFile,
            fileToData,
            watchFile,
        } = this.options

        this.data = options.initData
        if (fs.existsSync(filePath)) {
            this.data = fileToData?.(filePath)
        } else if (initData && dataToFile) {
            const dirname = path.dirname(filePath)
            if (!fs.existsSync(dirname)) {
                fs.mkdirSync(dirname, { recursive: true })
            }
            fs.writeFileSync(filePath, dataToFile(initData))
        }

        if (watchFile) {
            this.startWatching()
        }

        if (autoSave) {
            // 根据持久化频率保存文件
            this.save_timer = setInterval(() => {
                if (this.isUpdating) return;
                try {
                    this.isUpdating = true;
                    fs.writeFileSync(filePath, dataToFile(this.data));
                } catch (error) {
                    logger.error('自动保存失败:', error);
                } finally {
                    this.isUpdating = false;
                }
            }, this.options.flushInterval);
        }
    }

    private startWatching = () => {
        const { filePath, fileToData, onFileChange } = this.options

        this.watcher = fs.watch(filePath, (eventType) => {
            if (eventType !== 'change' || this.isUpdating) return;
            const now = Date.now();
            if (now - this.lastUpdateTime < this.DEBOUNCE_TIME) return;
            this.lastUpdateTime = now;

            try {
                this.isUpdating = true;
                const oldData = this.data
                const newData = fileToData(filePath);
                this.data = newData;
                onFileChange(newData, oldData);
            } catch (error) {
                logger.error('文件监听更新失败:', error);
            } finally {
                this.isUpdating = false;
            }
        });

        // 处理监听器错误
        this.watcher.on('error', (error) => {
            logger.error('文件监听错误:', error);
        });
    }

    /**
     * 修改数据并持久化，autoSave = true 时，仅修改数据，持久化使用定时器实现
     * @param data 需要修改的数据，不提供不修改
     * @returns 
     */
    update = (data?: T) => {
        if (data) {
            this.data = data;
        }
        const {
            autoSave,
            filePath,
            dataToFile,
            flushInterval,
        } = this.options
        if (autoSave) {
            // 自动保存模式下，不处理
            return;
        }
        if (this.save_timer) {
            clearTimeout(this.save_timer)
        }
        if (dataToFile) {
            this.save_timer = setTimeout(() => {
                this.isUpdating = true
                try {
                    fs.writeFileSync(filePath, dataToFile(this.data))
                } catch (error) {
                    logger.error('数据持久化失败:', error)
                } finally {
                    this.isUpdating = false
                }
            }, flushInterval)
        }
    }

    destroy = () => {
        if (this.save_timer) {
            if (this.options.autoSave) {
                clearInterval(this.save_timer);
            } else {
                clearTimeout(this.save_timer);
            }
        }
        if (this.watcher) {
            this.watcher.close()
        }
    }
}